package com.sinnatec.collection;

import com.sinnatec.lang.ObjectUtil;
import com.sinnatec.lang.StringUtil;
import org.apache.commons.collections4.*;


import java.io.PrintStream;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class MapUtil {
    private MapUtil(){

    }
    public static boolean isEmpty(Map<?, ?> map) {
        return MapUtils.isEmpty(map);
    }

    public static <K, V> V getObject(Map<? super K, V> map, K key) {
        return MapUtils.getObject(map,key);
    }

    public static <K> String getString(Map<? super K, ?> map, K key) {
        return MapUtils.getString(map,key);
    }

    public static <K> Boolean getBoolean(final Map<? super K, ?> map, final K key) {
        return MapUtils.getBoolean(map,key);
    }

    public static <K> Number getNumber(final Map<? super K, ?> map, final K key) {
        return MapUtils.getNumber(map,key);
    }

    public static <K> Byte getByte(final Map<? super K, ?> map, final K key){
        return MapUtils.getByte(map,key);
    }

    public static <K> Short getShort(final Map<? super K, ?> map, final K key){
        return MapUtils.getShort(map,key);
    }

    public static <K> Integer getInteger(final Map<? super K, ?> map, final K key){
        return MapUtils.getInteger(map,key);
    }

    public static <K> Long getLong(final Map<? super K, ?> map, final K key){
        return MapUtils.getLong(map,key);
    }

    public static <K> Float getFloat(final Map<? super K, ?> map, final K key){
        return MapUtils.getFloat(map,key);
    }

    public static <K> Double getDouble(final Map<? super K, ?> map, final K key){
        return MapUtils.getDouble(map,key);
    }

    public static <K> Map<?, ?> getMap(final Map<? super K, ?> map, final K key){
        return MapUtils.getMap(map,key);
    }

    public static <K, V> V getObject(final Map<K, V> map, final K key, final V defaultValue) {
        return MapUtils.getObject(map,key,defaultValue);
    }

    public static <K> String getString(final Map<? super K, ?> map, final K key, final String defaultValue) {
        return MapUtils.getString(map,key,defaultValue);
    }

    public static <K> Boolean getBoolean(final Map<? super K, ?> map, final K key, final Boolean defaultValue) {
        return MapUtils.getBoolean(map,key,defaultValue);
    }

    public static <K> Number getNumber(final Map<? super K, ?> map, final K key, final Number defaultValue) {
        return MapUtils.getNumber(map,key,defaultValue);
    }

    public static <K> Byte getByte(final Map<? super K, ?> map, final K key, final Byte defaultValue) {
        return MapUtils.getByte(map,key,defaultValue);
    }

    public static <K> Short getShort(final Map<? super K, ?> map, final K key, final Short defaultValue) {
        return MapUtils.getShort(map,key,defaultValue);
    }

    public static <K> Integer getInteger(final Map<? super K, ?> map, final K key, final Integer defaultValue) {
        return MapUtils.getInteger(map,key,defaultValue);
    }

    public static <K> Long getLong(final Map<? super K, ?> map, final K key, final Long defaultValue) {
        return MapUtils.getLong(map,key,defaultValue);
    }

    public static <K> Float getFloat(final Map<? super K, ?> map, final K key, final Float defaultValue) {
        return MapUtils.getFloat(map,key,defaultValue);
    }

    public static <K> Double getDouble(final Map<? super K, ?> map, final K key, final Double defaultValue) {
        return MapUtils.getDouble(map,key,defaultValue);
    }

    public static <K> Map<?, ?> getMap(final Map<? super K, ?> map, final K key, final Map<?, ?> defaultValue) {
        return MapUtils.getMap(map,key,defaultValue);
    }

    public static <K> boolean getBooleanValue(final Map<? super K, ?> map, final K key) {
        return MapUtils.getBooleanValue(map,key);
    }

    public static <K> byte getByteValue(final Map<? super K, ?> map, final K key) {
        return MapUtils.getByteValue(map,key);
    }

    public static <K> short getShortValue(final Map<? super K, ?> map, final K key) {
        return MapUtils.getShortValue(map,key);
    }

    public static <K> int getIntValue(final Map<? super K, ?> map, final K key) {
        return MapUtils.getIntValue(map,key);
    }

    public static <K> long getLongValue(final Map<? super K, ?> map, final K key) {
        return MapUtils.getLongValue(map,key);
    }

    public static <K> float getFloatValue(final Map<? super K, ?> map, final K key) {
        return MapUtils.getFloatValue(map,key);
    }

    public static <K> double getDoubleValue(final Map<? super K, ?> map, final K key) {
        return MapUtils.getDoubleValue(map,key);
    }

    public static <K> boolean getBooleanValue(final Map<? super K, ?> map, final K key, final boolean defaultValue) {
        return MapUtils.getBooleanValue(map,key,defaultValue);
    }

    public static <K> byte getByteValue(final Map<? super K, ?> map, final K key, final byte defaultValue) {
        return MapUtils.getByteValue(map,key,defaultValue);
    }

    public static <K> short getShortValue(final Map<? super K, ?> map, final K key, final short defaultValue) {
        return MapUtils.getShortValue(map,key,defaultValue);
    }

    public static <K> int getIntValue(final Map<? super K, ?> map, final K key, final int defaultValue) {
        return MapUtils.getIntValue(map,key,defaultValue);
    }

    public static <K> long getLongValue(final Map<? super K, ?> map, final K key, final long defaultValue) {
        return MapUtils.getLongValue(map,key,defaultValue);
    }

    public static <K> float getFloatValue(final Map<? super K, ?> map, final K key, final float defaultValue) {
        return MapUtils.getFloatValue(map,key,defaultValue);
    }

    public static <K> double getDoubleValue(final Map<? super K, ?> map, final K key, final double defaultValue) {
        return MapUtils.getDoubleValue(map,key,defaultValue);
    }

    public static <K, V> Properties toProperties(final Map<K, V> map) {
        return MapUtils.toProperties(map);
    }

    public static Map<String, Object> toMap(final ResourceBundle resourceBundle) {
        return MapUtils.toMap(resourceBundle);
    }

    public static void verbosePrint(final PrintStream out, final Object label, final Map<?, ?> map) {
        MapUtils.verbosePrint(out,label,map);
    }

    public static void debugPrint(final PrintStream out, final Object label, final Map<?, ?> map) {
        MapUtils.debugPrint(out,label,map);
    }

    public static <K, V> Map<V, K> invertMap(final Map<K, V> map) {
        return MapUtils.invertMap(map);
    }

    public static <K> void safeAddToMap(final Map<? super K, Object> map, final K key, final Object value)
            throws NullPointerException {
        MapUtils.safeAddToMap(map,key,value);
    }

    public static <K, V> Map<K, V> putAll(final Map<K, V> map, final Object[] array) {
        return MapUtils.putAll(map,array);
    }

    public static <K,V> Map<K,V> emptyIfNull(final Map<K,V> map) {
        return MapUtils.emptyIfNull(map);
    }

    public static boolean isNotEmpty(final Map<?,?> map) {
        return MapUtils.isNotEmpty(map);
    }

    public static <K, V> Map<K, V> synchronizedMap(final Map<K, V> map) {
        return MapUtils.synchronizedMap(map);
    }

    public static <K, V> Map<K, V> unmodifiableMap(final Map<? extends K, ? extends V> map) {
        return MapUtils.unmodifiableMap(map);
    }

    public static <K, V> IterableMap<K, V> predicatedMap(final Map<K, V> map, final Predicate<? super K> keyPred,
                                                         final Predicate<? super V> valuePred) {
        return MapUtils.predicatedMap(map, keyPred, valuePred);
    }
    public static <K, V> IterableMap<K, V> transformedMap(final Map<K, V> map,
                                                          final Transformer<? super K, ? extends K> keyTransformer,
                                                          final Transformer<? super V, ? extends V> valueTransformer) {
        return MapUtils.transformedMap(map,keyTransformer,valueTransformer);
    }

    public static <K, V> IterableMap<K, V> fixedSizeMap(final Map<K, V> map) {
        return MapUtils.fixedSizeMap(map);
    }

    public static <K, V> IterableMap<K, V> lazyMap(final Map<K, V> map, final Factory<? extends V> factory) {
        return MapUtils.lazyMap(map,factory);
    }

    public static <K, V> IterableMap<K, V> lazyMap(final Map<K, V> map,
                                                   final Transformer<? super K, ? extends V> transformerFactory) {
        return MapUtils.lazyMap(map,transformerFactory);
    }
    public static <K, V> OrderedMap<K, V> orderedMap(final Map<K, V> map) {
        return MapUtils.orderedMap(map);
    }

    public static <K, V> SortedMap<K, V> synchronizedSortedMap(final SortedMap<K, V> map) {
        return MapUtils.synchronizedSortedMap(map);
    }

    public static <K, V> SortedMap<K, V> unmodifiableSortedMap(final SortedMap<K, ? extends V> map) {
        return MapUtils.unmodifiableSortedMap(map);
    }

    public static <K, V> SortedMap<K, V> predicatedSortedMap(final SortedMap<K, V> map,
                                                             final Predicate<? super K> keyPred, final Predicate<? super V> valuePred) {
        return MapUtils.predicatedSortedMap(map,keyPred,valuePred);
    }

    public static <K, V> SortedMap<K, V> transformedSortedMap(final SortedMap<K, V> map,
                                                              final Transformer<? super K, ? extends K> keyTransformer,
                                                              final Transformer<? super V, ? extends V> valueTransformer) {
        return MapUtils.transformedSortedMap(map,keyTransformer,valueTransformer);
    }

    public static <K, V> SortedMap<K, V> fixedSizeSortedMap(final SortedMap<K, V> map) {
        return MapUtils.fixedSizeSortedMap(map);
    }

    public static <K, V> SortedMap<K, V> lazySortedMap(final SortedMap<K, V> map, final Factory<? extends V> factory) {
        return MapUtils.lazySortedMap(map, factory);
    }

    public static <K, V> SortedMap<K, V> lazySortedMap(final SortedMap<K, V> map,
                                                       final Transformer<? super K, ? extends V> transformerFactory) {
        return MapUtils.lazySortedMap(map, transformerFactory);
    }

    public static <K, V> void populateMap(final Map<K, V> map, final Iterable<? extends V> elements,
                                          final Transformer<V, K> keyTransformer) {
        populateMap(map, elements, keyTransformer, TransformerUtils.<V>nopTransformer());
    }

    public static <K, V, E> void populateMap(final Map<K, V> map, final Iterable<? extends E> elements,
                                             final Transformer<E, K> keyTransformer,
                                             final Transformer<E, V> valueTransformer) {
        MapUtils.populateMap(map,elements,keyTransformer,valueTransformer);
    }

    public static <K, V> IterableMap<K, V> iterableMap(final Map<K, V> map) {
        return MapUtils.iterableMap(map);
    }

    public static <K, V> IterableSortedMap<K, V> iterableSortedMap(final SortedMap<K, V> sortedMap) {
        return MapUtils.iterableSortedMap(sortedMap);
    }

    public static int size(final Map<?, ?> map) {
        return MapUtils.size(map);
    }

    public static <K, V> String toKeyValuePairString(Map<K,V> map,String nameSeparator, String valueSeparator){
        if(isEmpty(map)){
            return StringUtil.EMPTY;
        }
        TreeMap<K,V> treeMap = new TreeMap<>(map);
        List<String> pair = new ArrayList<>();
        for(Map.Entry<K,V> entry:treeMap.entrySet()){
            String pairString = ObjectUtil.toString(entry.getKey())+nameSeparator+ObjectUtil.toString(entry.getValue());
            pair.add(pairString);
        }
        return String.join(valueSeparator,pair);
    }

    public static <K, V> String toKeyValuePairString(Map<K,V> map){
        return toKeyValuePairString(map,StringUtil.EQUAL_SIGN,StringUtil.AMPERSAND);
    }

    public static boolean containsKeyAny(Map<?, ?> map,Object...key){
        for(Object k:key){
            if(map.containsKey(k)){
                return true;
            }
        }
        return false;
    }

    public static <K, V> HashMap<K, V> newHashMap() {
        return new HashMap<>();
    }

    public static <K, V> HashMap<K, V> newHashMap(Map<? extends K, ? extends V> map) {
        return new HashMap<>(map);
    }

    public static <K, V> LinkedHashMap<K, V> newLinkedHashMap() {
        return new LinkedHashMap<>();
    }

    public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(Map<? extends K, ? extends V> map) {
        return new LinkedHashMap<>(map);
    }

    public static <K, V> ConcurrentMap<K, V> newConcurrentMap() {
        return new ConcurrentHashMap<>();
    }

    public static <K extends Comparable, V> TreeMap<K, V> newTreeMap() {
        return new TreeMap<>();
    }

    public static <K, V> TreeMap<K, V> newTreeMap(SortedMap<K, ? extends V> map) {
        return new TreeMap<>(map);
    }

    public static <C, K extends C, V> TreeMap<K, V> newTreeMap(Comparator<C> comparator) {
        return new TreeMap<>(comparator);
    }

}
